/*******************************************************\
|* Author: Trevor Sundberg
\*******************************************************/

// Includes
#include "SkugoBuffer.hpp"
#include "SkugoDebug.hpp"
#include <cstring>

namespace Skugo
{
  // Constructor
  Buffer::Buffer()
  {
    // Start off at position zero
    mPosition = 0;

    // Reserve space for efficiency
    mData.reserve(64);

    // We have no user-data
    mUserData = NULL;
  }

  // Constructor that makes the buffer read and write to the given data
  Buffer::Buffer(const char* data, sizeType size)
  {
    // Start off at position zero
    mPosition = 0;

    // Save the user-data
    mUserData = const_cast<char*>(data);

    // Store away the size of the user data
    mUserDataSize = size;
  }

  // Get the size of the buffer
  sizeType Buffer::GetSize() const
  {
    return mPosition;
  }

  // Get the position of the buffer (same as the size)
  sizeType Buffer::GetPosition() const
  {
    return mPosition;
  }

  // Set the position manually
  void Buffer::SetPosition(sizeType position)
  {
    mPosition = position;
  }

  // Reset the position
  void Buffer::ResetPosition()
  {
    mPosition = 0;
  }

  // Get the data from the buffer
  char* Buffer::GetData() const
  {
    // If we have user data, then return that!
    if (mUserData != NULL)
      return mUserData;

    // If the data is empty...
    if (mData.empty())
    {
      // Return a NULL pointer since we have nothing to give back
      return NULL;
    }
    else
    {
      // Otherwise, give them the buffer data
      return const_cast<char*>(&mData.front());
    }
  }

  // Write raw data to the buffer
  void Buffer::Write(const void* data, sizeType size)
  {
    // If we have no data to send, skip this part
    if (size == 0)
    {
      return;
    }

    // Resize the data
    AddSize(size);

    // Get the original position
    char* start = GetData() + mPosition;

    // Copy the data into our newly allocated portion
    std::memcpy(start, data, size);

    // Finally, move the position forward
    mPosition += size;
  }

  // Read raw data from the buffer
  void Buffer::Read(void* dataOut, sizeType size)
  {
    // Get the original position
    char* start = GetData() + mPosition;

    // Copy the data into the output
    memcpy(dataOut, start, size);

    // Finally, move the position forward
    mPosition += size;
  }

  // Add to the size of the buffer
  void Buffer::AddSize(sizeType amount)
  {
    // Resizing does nothing if we're using user-data
    // However, we do need to do some error checking...
    if (mUserData != NULL)
    {
      // Do error checking, then return
      SkugoErrorIf(mPosition + amount > mUserDataSize, "Attempting to get data past the end of the user-provided buffer!");
      return;
    }

    // Resize the data
    mData.resize(mPosition + amount);
  }
}